import cgi
import os.path
import re
from xml.sax.saxutils import unescape

from paste.request import parse_dict_querystring, construct_url
from paste.response import replace_header
from httpencode import get_format
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
from pygments.util import ClassNotFound
from jsonstore import JSONStore
#from shrubbery import Template
from template import Template
import ElementSoup
from elementtree import ElementTree as etree
ElementSoup.ET = etree

from webskine.auth import MethodDigestMiddleware


def make_app(global_conf, dsn, templates, username, password, realm='webskine', title='A webskine blog', number_of_entries=10, **kwargs):
    responder = WebskineResponder(templates, title, **kwargs)
    store = JSONStore(dsn, number_of_entries=int(number_of_entries), responder=responder)
    app = MethodDigestMiddleware(store, username, password, realm)
    return app


class WebskineResponder(object):
    def __init__(self, template_dir, title, **kwargs):
        self.template_dir = template_dir
        self.templates = {}
        kwargs['title'] = cgi.escape(title)
        self.kwargs = kwargs

    def __call__(self, output, content_type=None, headers=None):
        if headers is None: headers = []

        def app(environ, start_response, exc_info=None):
            # Return JSON response.
            if 'json' in environ.get('HTTP_ACCEPT', ''):
                responder = get_format('json').responder
                app = responder(output, content_type, headers)
                return app(environ, start_response)

            # Get template and content_type.
            query = parse_dict_querystring(environ)
            name = query.get('t', 'default')
            template, new_content_type = self.get_template(name)

            # Apply template to JSON object.
            global_conf = self.kwargs.copy()
            global_conf['ROOT'] = construct_url(environ, 
                    with_path_info=False, with_query_string=False)
            template = template.process(global_conf, escape=False, remove_empty_nodes=False)
            formatted = template.process(output, escape=False)

            # Syntax highlight.
            #formatted = soup_highlight(formatted)

            replace_header(headers, 'Content-type', new_content_type)
            start_response("200 OK", headers)
            return [str(formatted)]
            
        return app

    def get_template(self, name):
        # Get template from cache, or build it if it has
        # been modified since creation.
        path = os.path.join(self.template_dir, name + '.shrb')
        mtime = os.path.getmtime(path)
        if (name not in self.templates or 
                mtime != self.templates[name][0]):
            f = open(path)
            new_content_type = f.readline().strip()  # remove \n from line!
            parser = ElementSoup.parse
            self.templates[name] = (mtime, Template(f, parser),
                    new_content_type)
            f.close()
        return self.templates[name][1:]


def soup_highlight(tree):
    tree = tree.copy()
    nodes = tree.findAll("code", attrs={"class": re.compile(".*")})
    for node in nodes:
        if node.parent.name == 'pre' and node.string:
            lang = node['class']
            if lang == 'shrubbery': lang = 'smarty'
            try:
                lexer = get_lexer_by_name(lang, stripall=True)
            except ClassNotFound:
                lexer = get_lexer_by_name('text', stripall=True)
            formatter = HtmlFormatter(linenos=False, cssclass="source")
            repl = highlight(unescape(node.string), lexer, formatter)
            node.parent.replaceWith(repl)
    return tree
